from typing import List, Dict
import pandas as pd
from mg_app_framework import get_organization, get_context, update_context

from common.basic_mongo import get_mongo_collection
from common.utils import datetime_to_sting, string_to_datetime
from service_log_viewer.servce_constant import DB_ACCESS_LOG, PaginationNode, TableSelect, DB_ACCESS_LOG_CONFIG, \
    GROUP_DEVICE_STRUCTURE


async def filter_servie_log_header() -> Dict:
    """
    下拉选择框
    """
    await group_device_config_context()
    func_result = {
        "process_code_select": get_context("process_code_select"),
        "api_string_select": get_context("api_string_select"),
        "user_code_dict": get_context("user_code_select_list"),
        "api_response_code_select": TableSelect.API_RESPONSE_CODE,
    }
    return func_result


async def group_device_config_context():
    web_layout_handle = get_mongo_collection(collection_name="web_layout_application")
    device_code_mapper = get_context("device_code_mapper")
    process_label = {}
    async for rcd in web_layout_handle.aggregate(GROUP_DEVICE_STRUCTURE):
        produce_unit_code_list = process_label.setdefault(rcd["produce_unit_code"], [])
        for r in rcd.get("device_info") or []:
            device_code = r["device_code"]
            device_name = r["device_name"]
            device_code_mapper[device_code] = device_name
            produce_unit_code_list.append(
                {
                    "label": device_name,
                    "prop": device_code
                }
            )
    production_config_handle = get_mongo_collection(
        collection_name="production_config_mgm_process_info",
        database_name=f"{get_organization()}_config",
    )
    process_code_select = []
    process_code_mapper = get_context("process_code_mapper")
    async for rcd in production_config_handle.find(
            {}, {"_id": 0, "工序编码": 1, "工序名称": 1, "生产单元编码": 1}):
        process_code_select.append(
            {
                "label": rcd.get("工序名称"),
                "prop": rcd.get("工序编码"),
                "children": process_label.get(rcd.get("生产单元编码")) or []
            }
        )
        process_code_mapper[rcd.get("工序编码")] = rcd.get("工序名称")
    update_context("process_code_select", process_code_select)


async def filter_service_logs(
        *,
        process_code: str,
        device_code: str,
        api_string: str,
        api_response_code: str,
        time_section: List,
        pagination_node: PaginationNode = None,
        **kwargs
) -> Dict:
    mongo_query = {}
    if process_code:
        mongo_query["process_code"] = process_code
    if device_code:
        mongo_query["equip_code"] = device_code
    if api_string:
        mongo_query["url"] = api_string
    if api_response_code:
        mongo_query["code"] = api_response_code
    if time_section:
        mongo_query.update({
            "time": {
                "$gte": time_section[0],
                "$lte": time_section[1]
            }
        })
    access_log_handler = get_mongo_collection(
        collection_name=DB_ACCESS_LOG,
        database_name=f"idi_{get_organization()}_upper_pc",
    )
    func_result = {
        "data": [],
        "total": await access_log_handler.count_documents(mongo_query)
    }
    query_projection = {
        "_id": 1,
        "process_code": 1,
        "equip_code": 1,
        "time": 1,
        "url": 1,
        "cost_time": 1,
        "code": 1,
        "user_code": 1
    }
    if pagination_node:
        access_logs = access_log_handler.find(
            mongo_query,
            limit=pagination_node.get_limit(),
            skip=pagination_node.get_skip(),
            sort=[("time", -1)],
            projection=query_projection
        )
    else:
        access_logs = access_log_handler.find(
            mongo_query,
            sort=[("time", -1)],
            projection=query_projection
        )
    user_code_dict = get_context("user_code_dict")
    api_string_mapper = get_context("api_string_mapper")
    device_code_mapper = get_context("device_code_mapper")
    process_code_mapper = get_context("process_code_mapper")
    async for item in access_logs:
        device_code = item.get("equip_code")
        process_code = item.get("process_code")
        user_code = item.get("user_code")
        url = item.get("url")
        tmp_itme = {
            "uid": str(item["_id"]),
            "process_code": process_code,
            "process_name": process_code_mapper.get(process_code),
            "device_code": device_code,
            "device_name": device_code_mapper.get(device_code),
            "cost_time": f"{item['cost_time']}ms",
            "url": url,
            "url_name": api_string_mapper.get(url),
            "time": datetime_to_sting(item["time"]) if item["time"] else "",
            "code": "成功" if item["code"] == "success" else "失败",
            "user_code": user_code,
            "user_name": user_code_dict.get(user_code)
        }
        func_result["data"].append(tmp_itme)
    return func_result


async def filter_target_servie_log(uid):
    access_log_handler = get_mongo_collection(
        collection_name=DB_ACCESS_LOG,
        database_name=f"idi_{get_organization()}_upper_pc",
    )
    log_item = await access_log_handler.find_one({
        "_id": uid
    }, projection={"_id": 0, "params": 1, "response": 1, "code": 1, "info": 1, "error": 1})
    func_result = {
        "params": log_item.get("params"),
        "response": {
            "code": log_item.get("code"),
            "data": log_item.get("response"),
            "info": log_item.get("info"),
        },
        "error": log_item.get("error")
    }
    return func_result


async def filter_server_log_config():
    access_log_handler = get_mongo_collection(
        collection_name=DB_ACCESS_LOG_CONFIG,
        database_name=f"idi_{get_organization()}_upper_pc",
    )
    func_result = []
    async for rcd in access_log_handler.find({}, projection={"_id": 0}):
        func_result.append({
            "url": rcd["url"],
            "url_name": rcd["url_name"],
        })

    return func_result


async def import_server_log_config(file_path: str):
    df = pd.read_excel(
        file_path,
        converters={
            u'接口名称': str,
            u'接口url': str,
        })
    df.fillna(value="", inplace=True)
    insert_records = []
    stock_code_set = set()
    api_string_select = []
    api_string_mapper = {}
    for index, one_ceil in df.iterrows():
        if one_ceil["接口名称"] in stock_code_set:
            raise AttributeError(
                "[{}] 导入数据格式异常, 接口名称:{} 重复".format(index + 1, one_ceil["接口名称"]))
        stock_code_set.add(one_ceil["接口名称"])
        url_name = one_ceil["接口名称"].strip()
        url = one_ceil["接口url"].strip()
        insert_records.append({
            "url_name": url_name,
            "url": url
        })
        api_string_select.append({
            "label": url_name,
            "prop": url
        })
        api_string_mapper[url] = url_name
    access_log_config_handler = get_mongo_collection(
        collection_name=DB_ACCESS_LOG_CONFIG,
        database_name=f"idi_{get_organization()}_upper_pc",
    )
    await access_log_config_handler.delete_many({})
    await access_log_config_handler.insert_many(insert_records, ordered=False)
    update_context("api_string_select", api_string_select)
    update_context("api_string_mapper", api_string_mapper)


async def upload_server_log_config(file_path: str):
    access_log_config_handler = get_mongo_collection(
        collection_name=DB_ACCESS_LOG_CONFIG,
        database_name=f"idi_{get_organization()}_upper_pc",
    )
    export_result = []
    async for rcd in access_log_config_handler.find({}, {"_id": 0}):
        export_result.append(rcd)

    export_result = list(export_result)
    pd_excel_data_frame = pd.DataFrame(export_result, columns=[
        "url_name",
        "url",
    ])
    pd_excel_data_frame.to_excel(file_path, index=False, header=[
        "接口名称",
        "接口url",
    ])

    return export_result
